/*
 * main.c
 *
 *  Created on: Feb 16, 2012
 *      Author: User
 */


#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "process.h"
#include "pcb.h"
#include "queue.h"
#include "timer.h"
#include "io_auxillary.h"
#include "scheduler.h"
#include "cpu.h"
#include "keyboard.h"

#define MAX_SEMAPHORE 100
//input methods.
void get_input_num_processes(entry_process_numbers_str*);

//testing methods.
void test_process();
void test_process_print(process* process_ptr);
void test_pcb(pcb*);

void cpu_run(timer* timer_ptr, pcb** pcb_array, process** process_array, sched* sched_ptr);
void cpu_switch_context(int interrupt, pcb** curr_pcb, process** curr_process, sched* sched_ptr, pcb** pcb_array, process** process_array, int* pc, int* max_instructions, int* pid);

//processes setup methods
process** setup_processes(process** process_arr, int* num_process_types);
process* setup_calculator(process* process_ptr, int index);
process* setup_consumer(process* process_ptr, int index);
process* setup_producer(process* process_ptr, int index);
process* setup_UI(process* process_ptr, int index);

//pcb setup method
void setup_pcbs(pcb** pcb_array, process** process_array, int* num_process_types); //creates pcb array parallel to process array

//output methods.
void setup_request_output(int pid, int proc_type, int device_type,
		int next_process_pid, int next_process_type, process** process_arr, pcb** pcb_arr);
void setup_interrupt_output(int pid, int proc_type, int device_type,
		int next_process_pid, int next_process_type, process** process_arr, pcb** pcb_arr);
void setup_sema_output(int pid, int proc_type, int device_type,
		int next_process_pid, int next_process_type, process** process_arr,
		pcb** pcb_arr);

int main(void) {
	printf("Hello, World!!\n");

	//get input from user;
	entry_process_numbers_str* num_proc_str = (entry_process_numbers_str*) malloc(sizeof(entry_process_numbers_str));
	get_input_num_processes(num_proc_str);
	//printf("My count is: %d, %d, %d, %d", num_proc_str->num_calc, num_proc_str->num_cons_prod_pairs, num_proc_str->num_uis, num_proc_str->total_num_processes);

	ready_q_status = true; //true = not empty, false = empty
	//get user input for number of processes and quantity of different types of processes
	int sched_type = 0; //hardcode to RR

	int num_process_types[3];
	num_process_types[0] = num_proc_str->num_calc; //first process type input (calc)
	num_process_types[1] = num_proc_str->num_cons_prod_pairs; //first process type input (p/c pair)
	num_process_types[2] = num_proc_str->num_uis; //first process type input (ui)
	num_processes = num_proc_str->total_num_processes;

	//allocate shared memory for p/c pairs
	shared_memory = (int *) malloc(num_process_types[1]*sizeof(int));
	for (int i = 0; i < num_process_types[1]; i++) {
		shared_memory[i] = 0;
	}

	//set up processes
	process** processes = (process**) malloc(sizeof(process) * num_processes);
	processes = setup_processes(processes, num_process_types);

	//testing aux
	int flag_num_aux = 2;
	aux_flag = &flag_num_aux;  //initial value to not get aux running from start.
	pthread_t aux_thread;
	pthread_create(&aux_thread, NULL, run_auxiliary, (void*)aux_flag);

	//setup keyboard io
	int flag_num_key = 2;  //initial value to not get key running from start.
	key_flag = &flag_num_key;
	pthread_t key_thread;
	pthread_create(&key_thread, NULL, run_keyboard, (void*)key_flag);

	//set up pcb array
	pcb** pcb_array = (pcb**) malloc(sizeof(pcb) * num_processes);
	setup_pcbs(pcb_array, processes, num_process_types);

	//set up timer
	timer* timer_ptr = timer_init();
	pthread_t timer_thread;
	pthread_create(&timer_thread, NULL, timer_start, (void*) timer_ptr);

	//set up scheduler
	sched* sched_ptr = (sched*) malloc(sizeof(sched));
	scheduler_start(sched_ptr, num_processes, pcb_array, processes, sched_type);

	//----output methods---
	//setup_request_output(0, 0, 0, 1, 0, processes, pcb_array);
	//setup_interrupt_output(0, 0, 0, 1, 0, processes, pcb_array);
	//setup_sema_output(5, 2, 0, 6, 1, processes, pcb_array); //consumer
	cpu_run(timer_ptr, pcb_array, processes, sched_ptr);

//	q = populate_test_queue(q);
//	for (int i = 0; i < 2000000; i++);
}

void cpu_run(timer* timer_ptr, pcb** pcb_array, process** process_array, sched* sched_ptr) {
	//get handle to first pcb (first process setup)
	int pid = scheduler_switch_context(-1, sched_ptr, &ready_q_status);
	pcb* curr_pcb = pcb_array[pid];
	process* curr_process = process_array[pid];
	int pc = curr_pcb->next_step;
	int max_instructions = curr_process->total_num_steps;
	int keep_going = 1;
	while (true) {
		printf("\n\nstarting loop.\n");
		//check if timer interrupt fired
		if (timer_ptr->timer_interrupt == true) {
			//switch context
			printf("pcb pid before timer: %i\n", curr_pcb->pid);
			cpu_switch_context(TIMER, &curr_pcb, &curr_process, sched_ptr, pcb_array, process_array, &pc, &max_instructions, &pid);
			printf("pcb pid after timer: %i\n", curr_pcb->pid);
			printf("ready q after timer: %i\n", ready_q_status);
			//reset timer
			timer_ptr->timer_interrupt = false; //TODO - Needed to change Timer state otherwise if will continue to interrupt every loop.
		}

		//increment pcb step
		pc = (pc + 1) % max_instructions;

		//we might want to have a pause method here.....(maybe)

		//check if current process instruction is waiting on aux/keyboard
		int request = process_is_interrupted(process_array[pid], pc);
		printf("My request index is: %d\n", request);

		if (request != -1) {
			printf("***I'm interrupted by IPC request; type: %i***\n", process_array[pid]->requests[request]->type_of_request);
			printf("request index is: %d\n", request);

			curr_pcb->waiting_on = process_get_request_type(process_array[pid], request);
			printf("I'm waiting on: %d\n", curr_pcb->waiting_on);
			if(curr_pcb->waiting_on == KEYBOARD) {
				printf("pcb pid before keyboard: %i\n", curr_pcb->pid);
				cpu_switch_context(KEY, &curr_pcb, &curr_process, sched_ptr, pcb_array, process_array, &pc, &max_instructions, &pid);
				printf("pcb pid after keyboard: %i\n", curr_pcb->pid);
				printf("ready q after keyboard: %i\n", ready_q_status);
			} else
			if(curr_pcb->waiting_on == AUXILIARY){
				printf("I'm in the AUX and I'm waiting on : %d\n", curr_pcb->waiting_on);
//				printf("pcb pid before aux: %i\n", curr_pcb->pid);
				cpu_switch_context(AUX, &curr_pcb, &curr_process, sched_ptr, pcb_array, process_array, &pc, &max_instructions, &pid);
//				printf("pcb pid after aux: %i\n", curr_pcb->pid);
//				printf("ready q after aux: %i\n", ready_q_status);
			}
		}
//		//if current process is p/c, edit semaphore (and wake partner) or block
		if (curr_process->process_t == PRODUCER) { //check if current process is p
			printf("I'm a producer.\n");
			printf("memory location: %d\n", curr_pcb->owns);
			printf("value at memory location: %d\n", shared_memory[curr_pcb->owns]);
			fflush(stdout);
			if (shared_memory[curr_pcb->owns] < MAX_SEMAPHORE) { //increment semaphor, wake consumer
				printf("I'm below my semaphore.\n");
				shared_memory[curr_pcb->owns] = shared_memory[curr_pcb->owns] + 1;
				if (shared_memory[curr_pcb->owns] == 1) { //wake consumer when semaphore isn't empty
					handle_interrupt(SEMA, sched_ptr, &ready_q_status, curr_pcb->owns);
				}
				printf("semaphor: %i\n", shared_memory[curr_pcb->owns]);
			} else { //block this and schedule another process
				printf("I hit my semaphore.");
				//printf("waiting on: %i\n", curr_pcb->waiting_on);
				cpu_switch_context(SEMA, &curr_pcb, &curr_process, sched_ptr, pcb_array, process_array, &pc, &max_instructions, &pid);
			}
		} else if (curr_process->process_t == CONSUMER) { //check if current process is c
			if (shared_memory[curr_pcb->owns] > 0) { //decrement semaphor, wake producer
				shared_memory[curr_pcb->owns] = shared_memory[curr_pcb->owns] - 1;
				if (shared_memory[curr_pcb->owns] == MAX_SEMAPHORE-1) { //wake producer when semaphore isn't full
					handle_interrupt(SEMA, sched_ptr, &ready_q_status, curr_pcb->owns);
				}
//				printf("semaphor: %i\n", shared_memory[curr_pcb->owns]);
			} else { //block this and schedule another process
				cpu_switch_context(SEMA, &curr_pcb, &curr_process, sched_ptr, pcb_array, process_array, &pc, &max_instructions, &pid);
			}
		}

		//check for interrupts requiring BLOCKED processes to be set to RUNNABLE
		if (*aux_flag == 0) {
			handle_interrupt(AUX, sched_ptr, &ready_q_status, -1);
		}
		if (*key_flag == 0) {
			handle_interrupt(KEY, sched_ptr, &ready_q_status, -1);
		}

		//TEST PROCESS BEING HANDLED
		if (curr_process->process_t == PRODUCER) { //check if current process is p
			//printf("pid #%i is a PRODUCER!", pid);
		} else if (curr_process->process_t == CONSUMER) { //check if current process is c
			//printf("pid #%i is a CONSUMER!", pid);
		} else if (curr_process->process_t == CALCULATOR) { //check if current process is c
			//printf("pid #%i is a CALCULATOR!", pid);
		} else if (curr_process->process_t == UI) { //check if current process is c
			//printf("pid #%i is a UI!", pid);
		}
		//printf("; pc: %i\n", pc);

//		if(shared_memory[curr_pcb->owns] == 0){
//			printf("I'm the 0 add to semaphore.");
//		}
//		if(shared_memory[curr_pcb->owns] == 1) {
//			printf("Im the 1 add to semaphore.");
//		}
//
//		if(curr_pcb->owns == 1) {
//			keep_going = false;
//		}
	}
}

/**
 * Reducing redundant code for context switch.
 * The actual context switch is handled by scheduler,
 * This method just sets the pc
 */
void cpu_switch_context(int interrupt,
					pcb** curr_pcb,
					process** curr_process,
					sched* sched_ptr,
					pcb** pcb_array,
					process** process_array,
					int* pc,
					int* max_instructions,
					int* pid) {
	//save state of current pcb
	(*curr_pcb)->next_step = *pc;
	//switch processes
	*pid = scheduler_switch_context(interrupt, sched_ptr, &ready_q_status);
	(*curr_pcb) = pcb_array[*pid];
	(*curr_process) = process_array[*pid];
	//reset pc and max instructions for next pcb
	*pc = (*curr_pcb)->next_step;
	*max_instructions = (*curr_process)->total_num_steps;
}

process** setup_processes(process** process_arr, int* num_process_types){
	int max_calc_processes = num_process_types[0];
	int max_pc_processes = num_process_types[1];
	int max_ui_processes = num_process_types[2];
	int num_created_processes = 0;

	printf("#calc processes: %d\t", max_calc_processes);
	printf("#pc processes: %d\t", max_pc_processes);
	printf("#ui processes: %d\n", max_ui_processes);

	for(int num_calc_processes = 0; num_calc_processes < max_calc_processes; num_calc_processes++) {
		//calculator
		process* calc_process = (process*) malloc(sizeof(process));
		calc_process = setup_calculator(calc_process, num_created_processes);
		process_arr[num_created_processes++] = calc_process;
	}
	for(int num_pc_processes = 0; num_pc_processes < max_pc_processes; num_pc_processes++) {
		//consumer
		printf("\nsetup_processes: PC process number: %d\n", num_created_processes);
		process* cons_process = (process*) malloc(sizeof(process));
		cons_process = setup_consumer(cons_process, num_created_processes);
		process_arr[num_created_processes++] = cons_process;
		//producer
		printf("\nsetup_processes: PC process number: %d\n", num_created_processes);
		process* prod_process = (process*) malloc(sizeof(process));
		prod_process = setup_producer(prod_process, num_created_processes);
		process_arr[num_created_processes++] = prod_process;
	}
	for(int num_ui_processes = 0; num_ui_processes < max_ui_processes; num_ui_processes++) {
		process* ui_process = (process*) malloc(sizeof(process));
		ui_process = setup_UI(ui_process, num_created_processes);
		process_arr[num_created_processes++] = ui_process;
	}

//	for(int i = 0; i < 4; i++) {
//		test_process_print(process_arr[i]);
//	}

	printf("*Total number of created processes: %d\n", num_created_processes);

	return process_arr;
}


//process setup methods.
process* setup_calculator(process* process_ptr, int index) {
	int num_requests = index;
	if (num_requests == 0){
		num_requests = 1;
	}
	int num_steps = num_requests * 100;

	process_ptr = process_create(index, num_steps, 0, CALCULATOR, NULL);

	return process_ptr;
}

process* setup_consumer(process* process_ptr, int index) {
	int num_requests = index;
	if (num_requests == 0){
		num_requests = 1;
	}

	int num_steps = num_requests * 100;
	request** requests = (request**) malloc(sizeof(request) * num_requests);
	request* rqt;
	int step;
	printf("In the setup_consumer:\n");
	for(int i = 0; i < num_requests; i++) {
		rqt = (request*)malloc(sizeof(request));
		step = rand() % num_steps + 1;
		printf("Request #: %i\t", i);
		printf("Number of requests is: %d\t", num_requests);
		printf("Step number is: %i\t", step);
		rqt = create_request(step, AUXILIARY);
		printf("Request type is: %d\t\n", rqt->type_of_request);
		requests[i] = rqt;
		fflush(stdout);
	}

	process_ptr = process_create(index, num_steps, num_requests, CONSUMER, requests);

	for(int i = 0; i < num_requests; i++) {
		printf("*in setup_consumer: Request #: %i\t\n", i);
		printf("in setup_consumer: Request type is: %d\n", process_get_request_type(process_ptr, i));
		fflush(stdout);
	}

	request** req = process_ptr->requests;
	request* r;

	for(int i = 0; i < num_requests; i++) {
		r = req[i];
		//printf("---Request step: %i---\n", r->step);
	}

	//test_process_print(process_ptr);

	return process_ptr;
}

process* setup_producer(process* process_ptr, int index){
	int num_requests = index;
	if(num_requests == 0) {
		num_requests = 1;
	}

	int num_steps = num_requests * 100;
	request** requests = (request**) malloc(sizeof(request) * num_requests);
	request* rqt;
	int step;
	printf("In the setup_consumer:\n");
	for(int i = 0; i < num_requests; i++) {
		rqt = (request*)malloc(sizeof(request));
		step = rand() % num_steps + 1;
		printf("Request #: %i\t", i);
		printf("Number of requests is: %d\t", num_requests);
		printf("Step number is: %i\t", step);
		rqt = create_request(step, AUXILIARY);
		printf("Request type is: %d\t\n", rqt->type_of_request);
		requests[i] = rqt;
	}

	process_ptr = process_create(index, num_steps, num_requests, PRODUCER, requests);

	request** req = process_ptr->requests;
	request* r;

	for(int i = 0; i < num_requests; i++) {
		r = req[i];
		//printf("---Request step: %i---\n", r->step);
	}

	//test_process_print(process_ptr);

	return process_ptr;
}

process* setup_UI(process* process_ptr, int index) {
	int num_requests = index;
	if (num_requests == 0) {
		num_requests = 1;
	}
	int num_steps = num_requests * 100;

	request** requests = (request**) malloc(sizeof(request) * num_requests);
	request* rqt;
	int step;
	for(int i = 0; i < num_requests; i++) {
		rqt = (request*)malloc(sizeof(request));
		step = rand() % num_steps + 1;
		//printf("Step number is: %i\n", step);
		if (i%2 == 0){
			rqt = create_request(step, KEYBOARD);
		}
		else{
			rqt = create_request(step, AUXILIARY);
		}
		//printf("Rand number is: %i\n", step);
		requests[i] = rqt;
	}

	process_ptr = process_create(index, num_steps, num_requests, UI, requests);

	request** req = process_ptr->requests;
	request* r;

	for(int i = 0; i < num_requests; i++) {
		r = req[i];
		//printf("---Request step: %i---\n", r->step);
	}

	//test_process_print(process_ptr);

	return process_ptr;
}

void test_process_print(process* process_ptr){
	int num_requests = process_ptr->num_requests;
	printf("\nMy process contains: \n");
	printf("Number of requests: %i\n", process_ptr->num_requests);
	printf("Process ID number: %i\n", process_ptr->process_id);
	printf("Process Type %i\n", process_ptr->process_t);
	printf("Total number of steps: %i\n\n", process_ptr->total_num_steps);

	request** req_ptr_ptr = process_ptr->requests;
	request* req_ptr;

	for(int i = 0; i < num_requests; i++) {
		req_ptr = req_ptr_ptr[i];
		printf("My %i Request contains: \n", i + 1);
		printf("Number of steps: %i\n", req_ptr->step);
		printf("Type of request: %i\n", req_ptr->type_of_request);
		fflush(stdout);
	}
}

/**
 * Tests the process classes.
 */
 void test_process(){
	 printf("I'm inside test_process\n");

	int process_id = 0;
	int total_num_steps = 100;
	int num_requests = 2;

	//create requests
	//initialize request pointer array.
	request* requests[2];

	//create request zero and assign to request pointer array.
	request* request_zero = malloc(sizeof(request));
	request_zero = create_request(5, AUXILIARY);
	requests[0] = request_zero;

	//create request one and assign to request pointer array.
	request* request_one = malloc(sizeof(request));
	request_one = create_request(10, AUXILIARY);
	requests[1] = request_one;

	enum process_type pt = CALCULATOR;

	//create processes
	process* p = malloc(sizeof(process));
	p = process_create(process_id, total_num_steps, num_requests,
			pt, requests);

	printf("My process contains: \n");
	printf("Number of requests: %i\n", p->num_requests);
	printf("Process ID number: %i\n", p->process_id);
	printf("Process Type %i\n", p->process_t);
	printf("Total number of steps: %i\n\n", p->total_num_steps);

	request** req_ptr_ptr = (request**)p->requests;
	request* req_ptr = req_ptr_ptr[0];

	printf("My first Request contains: \n");
	printf("Number of steps: %i", req_ptr->step);

	req_ptr = req_ptr_ptr[1];

	printf("\n\nMy second Request contains: \n");
	printf("Number of steps: %i", req_ptr->step);
}

 void setup_pcbs(pcb** pcb_array, process** process_array, int* num_process_types) {
	 int num_created_pcbs = 0;
	 for(int process_type = 0; process_type < 3; process_type++) { //0=calc, 1=p/c, 2=ui
		 int max_this_type = num_process_types[process_type];
//		 printf("max this type: %i\n", max_this_type);
		 for(int num_type = 0; num_type < max_this_type; num_type++) {
//			 printf("pid: %i\n", num_created_pcbs);
			 pcb* pcb_ptr = pcb_new(process_array[num_created_pcbs]->process_id);
			 pcb_array[num_created_pcbs++] = pcb_ptr;
			 if(process_type == 1) { //p/c pair
//				 printf("pid: %i\n", num_created_pcbs);
				 pcb* pcb_ptr_pr = pcb_new(process_array[num_created_pcbs]->process_id);
				 pcb_ptr->owns = num_type;
				 pcb_ptr_pr->owns = num_type;
				 pcb_array[num_created_pcbs++] = pcb_ptr_pr;
			 }
		 }
	 }

	 //test
//	 printf("testing pcb\n");
//	 for(int i = 0; i < 4; i++) {
//		 test_pcb(pcb_array[i]);
//	 }
////	 set_blocked(pcb_array[2], 100);
//
//	 for(int i = 0; i < 4; i++) {
//		 test_pcb(pcb_array[i]);
//	 }
 }

void test_pcb(pcb* pcb_ptr) {
	printf("PID: %i\n", pcb_ptr->pid);
	char state_str[20]; //0=RUNNING, 1=BLOCKED, 2=RUNNABLE, 3=INTERRUPTED
	if (pcb_ptr->state == 0) { //
		strcpy(state_str, "RUNNING");
	} else if (pcb_ptr->state == 1) {
		strcpy(state_str, "BLOCKED");
	} else if (pcb_ptr->state == 2) {
		strcpy(state_str, "RUNNABLE");
	} else { //never used
		strcpy(state_str, "INTERRUPTED");
	}
//	printf("STATE: %s\n", state_str);
//	printf("OWNS: %i\n", pcb_ptr->owns);
}

void get_input_num_processes(entry_process_numbers_str* num_proc_str){
    char line[100];
    int value;
    int count = 0;

    //get number of calculator processes.
	printf("Welcome to our Operating Simulation Program!!!\n");
	printf("Please enter how many calculator processes you want: ");
	fflush(stdout);
	fgets(line, sizeof(line), stdin);
	sscanf(line, "%d", &value);
	num_proc_str->num_calc = value;
	count += value;
	printf("Number entered is: %d\n", num_proc_str->num_calc);

	//get number of consumer/producer pairs.
	printf("\nPlease enter how many consumer/producer pairs you want: ");
	fflush(stdout);
	fgets(line, sizeof(line), stdin);
	sscanf(line, "%d", &value);
	num_proc_str->num_cons_prod_pairs = value;
	count += value * 2;
	//printf("Number entered is: %d\n", num_proc_str->num_cons_prod_pairs);


	//get number of ui processes.
	printf("\nPlease enter how many user interface processes you want: ");
	fflush(stdout);
	fgets(line, sizeof(line), stdin);
	sscanf(line, "%d", &value);
	num_proc_str->num_uis = value;
	count += value;
	//printf("Number entered is: %d\n", num_proc_str->num_uis);

	//check count
	//printf("\nNumber of total processes: %d", count);
	num_proc_str->total_num_processes = count;
	//printf("\nNumber of processes stored: %d", num_proc_str->total_num_processes);
}

void setup_request_output(int pid, int proc_type, int device_type,
		int next_process_pid, int next_process_type, process** process_arr, pcb** pcb_arr) {
	int process_num = 0; //pid
	int process_type_int = 0; //process type
	device_type = 0; //device requested
	next_process_pid = 0;
	next_process_type = 0; //next de

	char* process_type_str[15];
	//get_req_out_string(process_type_str, process_type);
	if(process_type_int == 0) {
		*process_type_str = "Calculator";
	} else if(process_type_int == 1) {
		*process_type_str = "Producer";
	}else if(process_type_int == 2) {
		*process_type_str == "Consumer";
	}else {
		*process_type_str == "User Interface";
	}

	char* next_process_str[15];
	if(next_process_type == 0) {
		*next_process_str = "Calculator";
	} else if(next_process_type == 1) {
		*next_process_str = "Producer";
	}else if(next_process_type == 2) {
		*next_process_str == "Consumer";
	}else {
		*next_process_str == "User Interface";
	}

	char* device_type_str[15];
	*device_type_str = "place holder";
	if(device_type == 0) {
		*device_type_str = "Keyboard";
	} else {
		*device_type_str = "Auxiliary";
	}

	//Console out
	printf("\nProcess %d (%s) made a system call to device %d (%s).\n", process_num, *process_type_str, device_type, *device_type_str);
	printf("Scheduler: Running process %d (%s) next.\n", next_process_pid, *next_process_str);
	process* pro;
	for(int i = 0; i < num_processes; i++) {
		pro = process_arr[i];
		int type = pro->process_t;
		printf("\tProcess %i ", i);
		char* process_type_str[15];
		if( pro->process_t == 0) {
			printf("(Calculator)'s ");
		} else if(pro->process_t == 1) {
			printf("(Producer)'s ");
		}else if(pro->process_t == 2) {
			printf("(Consumer)'s ");
		}else {
			printf("(User Interface)'s ");
		}
		printf("state: ");
		int run_state = pcb_arr[i]->state;
		//printf("\nrun state: %i", run_state);

//	    RUNNING,
//	    BLOCKED,
//	    RUNNABLE,
//	    INTERRUPTED
		if (run_state == 0) {
			printf("RUNNING\n");
		} else if (run_state == 1) {
			printf("BLOCKED\n");
		} else {
			printf("RUNNABLE\n");
		}
		fflush(stdout);
	}
}

void setup_interrupt_output(int pid, int proc_type, int device_type,
		int next_process_pid, int next_process_type, process** process_arr,
		pcb** pcb_arr) {
		printf("I'm inside the setup_interrupt_output method.\n");
		int process_num = 0; //pid
		int process_type_int = 0; //process type
		device_type = 0; //device requested
		next_process_pid = 0;
		next_process_type = 0; //next de

		char* process_type_str[15];
		//get_req_out_string(process_type_str, process_type);
		if(process_type_int == 0) {
		*process_type_str = "Calculator";
		} else if(process_type_int == 1) {
		*process_type_str = "Producer";
		}else if(process_type_int == 2) {
		*process_type_str == "Consumer";
		}else {
		*process_type_str == "User Interface";
		}

		char* next_process_str[15];
		if(next_process_type == 0) {
		*next_process_str = "Calculator";
		} else if(next_process_type == 1) {
		*next_process_str = "Producer";
		}else if(next_process_type == 2) {
		*next_process_str == "Consumer";
		}else {
		*next_process_str == "User Interface";
		}

		char* device_type_str[15];
		*device_type_str = "place holder";
		if(device_type == 0) {
		*device_type_str = "Keyboard";
		} else {
		*device_type_str = "Auxiliary";
		}

		//Console out
		printf("Device %d (%s) produced an interrupt.\n", device_type, *device_type_str);
		printf("Scheduler: Running process %d (%s) next.\n", next_process_pid, *next_process_str);
		process* pro;
		for(int i = 0; i < num_processes; i++) {
		pro = process_arr[i];
		int type = pro->process_t;
		printf("\tProcess %i ", i);
		char* process_type_str[15];
		if( pro->process_t == 0) {
			printf("(Calculator)'s ");
		} else if(pro->process_t == 1) {
			printf("(Producer)'s ");
		}else if(pro->process_t == 2) {
			printf("(Consumer)'s ");
		}else {
			printf("(User Interface)'s ");
		}
		printf("state: ");
		int run_state = pcb_arr[i]->state;
		//printf("\nrun state: %i", run_state);

		//	    RUNNING,
		//	    BLOCKED,
		//	    RUNNABLE,
		//	    INTERRUPTED
		if (run_state == 0) {
			printf("RUNNING\n");
		} else if (run_state == 1) {
			printf("BLOCKED\n");
		} else {
			printf("RUNNABLE\n");
		}
		fflush(stdout);
	}
}

void setup_sema_output(int pid, int proc_type, int device_type,
		int next_process_pid, int next_process_type, process** process_arr,
		pcb** pcb_arr) {
		printf("I'm inside the setup_sema_output method.\n");
		int process_type_int = proc_type; //process type

		char* process_type_str[15];
		//get_req_out_string(process_type_str, process_type);
		if(proc_type == 0) {
		*process_type_str = "Calculator";
		} else if(proc_type == 1) {
		*process_type_str = "Producer";
		}else if(proc_type == 2) {
		*process_type_str == "Consumer";
		}else {
		*process_type_str == "User Interface";
		}

		char* next_process_str[15];
		if(next_process_type == 0) {
		*next_process_str = "Calculator";
		} else if(next_process_type == 1) {
		*next_process_str = "Producer";
		}else if(next_process_type == 2) {
		*next_process_str == "Consumer";
		}else {
		*next_process_str == "User Interface";
		}

		char* device_type_str[15];
		*device_type_str = "place holder";
		if(device_type == 0) {
		*device_type_str = "Keyboard";
		} else {
		*device_type_str = "Auxiliary";
		}

		//Console out
		if (process_type_int == 2){
			printf("Process %d (%s) attempted to decrement memory location %d\n", pid, *process_type_str, pcb_arr[pid]->owns);
		} else{
			printf("Process %d (%s) attempted to increment memory location %d\n", pid, *process_type_str, pcb_arr[pid]->owns);
		}
		printf("Scheduler: Running process %d (%s) next.\n", next_process_pid, *next_process_str);
		process* pro;
		for(int i = 0; i < num_processes; i++) {
		pro = process_arr[i];
		int type = pro->process_t;
		printf("\tProcess %i ", i);
		char* process_type_str[15];
		if( pro->process_t == 0) {
			printf("(Calculator)'s ");
		} else if(pro->process_t == 1) {
			printf("(Producer)'s ");
		}else if(pro->process_t == 2) {
			printf("(Consumer)'s ");
		}else {
			printf("(User Interface)'s ");
		}
		printf("state: ");
		int run_state = pcb_arr[i]->state;
		//printf("\nrun state: %i", run_state);

		//	    RUNNING,
		//	    BLOCKED,
		//	    RUNNABLE,
		//	    INTERRUPTED
		if (run_state == 0) {
			printf("RUNNING\n");
		} else if (run_state == 1) {
			printf("BLOCKED\n");
		} else {
			printf("RUNNABLE\n");
		}
		fflush(stdout);
	}
}
